﻿using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using Verification.Cache;
using Verification.ChartUtils;
using Verification.Mold;

namespace Verification.JigsawPuzzle
{
    /// <summary>
    /// 拼图认证 
    /// 默认信息
    /// 客户端私钥名称：name
    /// Cache默认过期时间：5分钟
    /// </summary>
    /// <typeparam name="D"></typeparam>
    public class JigsawPuzzle<D>
    {
        #region 基础配置
        /// <summary>
        /// 文件地址
        /// </summary>
        public string Path { get; set; }
        /// <summary>
        /// 文件类型
        /// 单文件写法：*.jpg,多文件写法：(*.jpg|*.png)
        /// </summary>
        public string FileType { get; set; }
        /// <summary>
        /// 客户端验证秘钥
        /// </summary>
        private string Name { get; set; }
        /// <summary>
        /// 客户端私钥名称，默认为name
        /// </summary>
        private string _CookieName { get; set; }
        private string CookieName
        {
            get
            {
                return _CookieName;
            }
            set
            {
                CookieName = value;
            }
        }
        /// <summary>
        /// 横坐标分成几份
        /// </summary>
        public int X { get; set; }
        /// <summary>
        /// 纵坐标分成几份
        /// </summary>
        public int Y { get; set; }
        /// <summary>
        /// 原图序号Id,需要传入
        /// </summary>
        public D[] Data { get; set; }
        /// <summary>
        /// Cache失效时
        /// </summary>
        public int CacheHours { get; set; }
        /// <summary>
        /// Cache失效分,默认5分钟过期
        /// </summary>
        public int CacheMin { get; set; }
        /// <summary>
        /// Cache失效秒
        /// </summary>
        public int CacheSec { get; set; }
       
        /// <summary>
        /// HttpContext
        /// </summary>
        public HttpContext HttpContext { get; set; }
        #endregion
        #region 异常返回信息
        /// <summary>
        /// 客户端私钥不存在
        /// </summary>
        public string NotNameError { get; set; }
        /// <summary>
        /// 验证码超时
        /// </summary>
        public string CacheTimeOutError { get; set; }
        /// <summary>
        /// 传入数据异常
        /// </summary>
        public string ArrIsNull { get; set; }
        /// <summary>
        /// 验证失败
        /// </summary>
        public string NotPass { get; set; }
        #endregion
        #region 获取信息

        //public Type ShowNameType() { return typeof(N); } //返回类型
        /// <summary>
        /// 获取传入序号类型
        /// </summary>
        /// <returns></returns>
        public Type ShowDataType() { return typeof(D); } //返回类型
        /// <summary>
        /// 获取客户端私钥
        /// </summary>
        /// <returns></returns>
        public string GetName() { return new CookieUtils(HttpContext).GetValue(CookieName); } 
        /// <summary>
        /// 获取客户端私钥名称
        /// </summary>
        /// <returns></returns>
        public string GetCookieName() { return CookieName; } 
        /// <summary>
        /// 获取原序号列表
        /// </summary>
        /// <returns></returns>
        public D[] GetData() { return Data; }
        #endregion
        public JigsawPuzzle()
        {
            _CookieName = "name";
            NotNameError = "用户签名不存在，请刷新后再试！";
            CacheTimeOutError = "验证码超时，请刷新后重试！";
            ArrIsNull= "数据异常，请刷新后再试！";
            NotPass = "验证码错误，请重试！";
            if (CacheHours == 0 && CacheMin == 0 && CacheSec == 0)
                CacheMin = 5;
        }
        #region 设置基础信息
        /// <summary>
        /// 自定义客户端缓存Name
        /// 必须要在生成验证码之前设置
        /// </summary>
        /// <param name="name"></param>
        public void SetName(string name)
        {
            //删除原来的Name
            new CookieUtils(HttpContext).DeleteCookie(CookieName);
            new CookieUtils(HttpContext).AddCookie(CookieName, Name.ToString());
            Name = name;
        }
        /// <summary>
        /// 设置客户端私钥名称
        /// </summary>
        /// <param name="name"></param>
        public void SetCookieName(string name)
        {
            //删除原来的Name
            _CookieName = name;
        }
        /// <summary>
        /// 验证客户端私钥是否存在，如果不存在则新增
        /// </summary>
        public void CheckName()
        {
            //查找是否存在相关cookie
            Name = new CookieUtils(HttpContext).GetValue(CookieName);
            if (string.IsNullOrWhiteSpace(Name))
            {
                //如果不存在则新增               
                //new CookieUtils(HttpContext).DeleteCookie(CookieName);
                Name = Guid.NewGuid().ToString();
                new CookieUtils(HttpContext).AddCookie(CookieName, Name);
            }
        }
        #endregion
        #region 拼图设置
        /// <summary>
        /// 生成拼图信息
        /// </summary>
        /// <param name="ids">Id列表</param>
        /// <param name="imgData">分割好的图，传入个空数组即可</param>
        /// <returns></returns>
        public bool GetJigsawPuzzzleData(ref D[] ids  ,ref string[] imgData)
        {
            if (string.IsNullOrWhiteSpace(CookieName))
                throw new ArgumentNullException("客户端秘钥名称不存在！");
            if (string.IsNullOrWhiteSpace(Path))
                throw new ArgumentNullException("请配置图库地址！");
            if (string.IsNullOrWhiteSpace(FileType))
                throw new ArgumentNullException("请配置图库文件类型！");          
            if(Data.Length<=0)
                throw new ArgumentNullException("请配置图集编号");
            if (X== 0)
                throw new ArgumentNullException("请配置横坐标拆分数量");
            if (Y == 0)
                throw new ArgumentNullException("请配置纵坐标拆分数量");
            if(HttpContext==null)
                throw new ArgumentNullException("请配置HttpContext");
            try
            {
                //验证Name
                CheckName();
                //获取指定图库下的所有图
                string[] files = Directory.GetFiles(Path, FileType);
                new CacheUtils().Set("VerCode_" + Name, Data, new TimeSpan(CacheHours, CacheMin, CacheSec));
                Random rd = new Random();
                int imgIndex = rd.Next(files.Length);
                //生成序号
                int[] number = new int[X * Y];
                for (int i = 0; i < number.Length; i++)
                    number[i] = i;
                //打乱序号
                UpsetUtils<int> disrupter = new UpsetUtils<int>(number);
                number = disrupter.GetDisruptedItems();

                Bitmap image = new Bitmap(files[imgIndex]);
                string[] image_Split_Base64 = ImageUtils.BreakUpTheFigure(X, Y, 0, 0, image);

                for (int i = 0; i < number.Length; i++)
                {
                    ids[i] = Data[number[i]];
                    imgData[i] = image_Split_Base64[number[i]];
                }
                return true;
            }
            catch(Exception ex)
            {
                throw new ArgumentNullException(ex.Message);
            }
           
        }
        /// <summary>
        /// 验证是图是否通过
        /// </summary>
        /// <param name="arr">用户提交的拼图Id列表</param>
        /// <returns></returns>
        public bool CheckJigsawPuzzzle(D[] arr)
        {
            try
            {
                if (string.IsNullOrWhiteSpace(CookieName))
                    throw new ArgumentNullException("客户端秘钥名称不存在！");
                if (HttpContext == null)
                    throw new ArgumentNullException("请配置HttpContext");
                Name = new CookieUtils(HttpContext).GetValue(CookieName);

                if (string.IsNullOrWhiteSpace(Name))
                    throw new ArgumentNullException(NotNameError);
                D[] list = new CacheUtils().Get<D[]>("VerCode_" + Name);
                if (list == null || list.Length <= 0)
                    throw new ArgumentNullException(CacheTimeOutError);
                if (arr.Length != list.Length)
                    throw new ArgumentNullException(ArrIsNull);
                for (int i = 0; i < arr.Length; i++)
                {
                    if (arr[i].ToString() != list[i].ToString())
                        throw new ArgumentNullException(NotPass);
                }
                return true;
            }
            finally
            {
                new CacheUtils().Remove("VerCode_" + Name);
                
            }

           
         

        }
        #endregion

    }
}
